﻿using ExcelUnity.Core;
using ExcelUnity.Exporter.Attributes;
using ExcelUnity.Exporter.Attributes.Styles;
using ExcelUnity.Exporter.Exporters;
using ExcelUnity.Exporter.Styles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ExcelUnity.Exporter.Wrappers.SheetWrapperBuilders
{
    public class DefaultTypeBuilder : BaseBuilder
    {
        private Dictionary<int, PropertyInfo> PropertyMap = new Dictionary<int, PropertyInfo>();

        public override List<ColumnAdapter> BuildColumnAdapter(ExportSheet sheet)
        {
            var type = sheet.DataType;
            var properties = type.GetProperties()
                                .Where(x => x.GetCustomAttribute(typeof(IgnoreColumnAttribute)) is null)
                                .ToList();

            var ret = new List<ColumnAdapter>();
            for (int i = 0; i < properties.Count; i++)
            {
                var property = properties[i];
                PropertyMap.Add(i, property);

                var name = property.GetCustomAttribute(typeof(ColumnNameAttribute)) is ColumnNameAttribute nameAttr ? nameAttr.Name : property.Name;

                var adapter = sheet.ToAdapter(i, name);

                if (property.GetCustomAttribute(typeof(ColumnWidthAttribute)) is ColumnWidthAttribute widthAttr)
                {
                    adapter.MinWidth = widthAttr.MinWidth;
                    adapter.MaxWidth = widthAttr.MaxWidth;
                }

                if (property.GetCustomAttribute(typeof(HeaderStyleAttribute)) is HeaderStyleAttribute headerAttr)
                    adapter.HeaderStyle = headerAttr.Style;

                if (property.GetCustomAttribute(typeof(ColumnStyleAttribute)) is ColumnStyleAttribute columnAttr)
                    adapter.ColumnStyle = columnAttr.Style;

                if (property.GetCustomAttribute(typeof(StringFormatterAttribute)) is StringFormatterAttribute formatAttr)
                    adapter.StringFormat = formatAttr.Format;

                if (property.GetCustomAttribute(typeof(MergeRowAttribute)) is MergeRowAttribute)
                    adapter.MergedRowByPrimaryKey = true;

                if (property.GetCustomAttribute(typeof(MergeRowAloneAttribute)) is MergeRowAloneAttribute)
                {
                    adapter.MergedRowAlone = true;
                }

                if (property.GetCustomAttribute(typeof(PrimaryKeyAttribute)) is PrimaryKeyAttribute)
                    adapter.IsPrimaryColumn = true;
                ret.Add(adapter);
            }

            return ret;
        }

        public override IEnumerable<ExportRowWrapper> FillDataRows(ExportSheet sheet, List<ColumnAdapter> columnAdapters, int rowIndex)
        {
            foreach (var data in sheet.Data)
            {
                var cells = new List<ExportCellWrapper>();
                foreach (var adapter in columnAdapters)
                {
                    var val = GetCellValue(PropertyMap[adapter.ColumnIndex], adapter, data);

                    var cell = new ExportCellWrapper(val, adapter);

                    if (adapter.SpecialCellStyle?.ContainsKey(val) ?? false)
                        cell.CellStyle = adapter.SpecialCellStyle[val];

                    //动态设置的单元格样式
                    var dynamicStylePair = new Dictionary<string, BaseStyle>();
                    if (typeof(DynamicCellStyle).IsAssignableFrom(data.GetType()))
                        dynamicStylePair = ((DynamicCellStyle)data).PropertyNameStylePair.ToDictionary(x => x.Key, x => x.Value);

                    if (dynamicStylePair.TryGetValue(PropertyMap[adapter.ColumnIndex].Name, out BaseStyle style))
                        cell.CellStyle = style;
                    cells.Add(cell);
                }

                yield return new ExportRowWrapper(cells, rowIndex++);
            }
        }

        private string GetCellValue(PropertyInfo property, ColumnAdapter adapter, object target)
        {
            var objectValue = property.GetValue(target);

            string cellValue = string.Empty;
            if (objectValue != null)
            {
                if (property.PropertyType == typeof(DateTime) || property.PropertyType == typeof(DateTime?))
                {
                    var format = adapter.StringFormat.IsNullOrWhiteSpace() ? ExportConfig.DefaultDateFormat : adapter.StringFormat;
                    cellValue = ((DateTime)objectValue).ToString(format);
                }
                else
                {
                    cellValue = objectValue.ToString();
                }
            }
            return cellValue;
        }
    }
}
